#pragma once

#include "adalog/buffer/BufferPoolManager.h"

namespace adalog
{
    class WriteBufferGuard
    {
        friend class BufferPoolManager;
    public:
        /**
         * @brief 只有BufferPoolManager能够创建有效的WriteBufferGuard对象，该默认构造函数是为了外部能够预先创建一个WriteBufferGuard对象，以便跨作用域传递
         */
        WriteBufferGuard() = default;
        /**
         * @brief 禁止拷贝构造和赋值构造
         */
        WriteBufferGuard(const WriteBufferGuard&) = delete;
        WriteBufferGuard& operator=(const WriteBufferGuard&) = delete;
        /**
         * @brief 允许移动构造和移动赋值
         */
        WriteBufferGuard(WriteBufferGuard&& other) noexcept;
        WriteBufferGuard& operator=(WriteBufferGuard&& other) noexcept;
        ~WriteBufferGuard();

        size_t GetBufferId() const;

        /**
         * @brief 获取缓冲区中可读数据的起始地址，从该起始地址开始有ReadableSize()个字节的数据可读，超出该范围的数据不可读。
         * @return 缓冲区中可读数据的起始地址
         */
        const char* GetDataBegin() const;

        /**
         * @return 从缓冲区的起始地址开始，到可读数据的末尾的字节数
         */
        size_t ReadableSize() const;

        /**
         * @brief 重置缓冲区
         */
        void Reset();

        /**
         * @brief 将从data开始的len字节数据追加写入缓冲区
         * @param data 待写入的数据的起始地址
         * @param len 待写入的数据的字节数。若len <= WritableSize()，则正常写入；否则，缓冲区会进行扩容以保证能够写入len个字节的数据。
         */
        void WriteData(const char* data, size_t len);

        /**
         * @return 缓冲区的可写入字节数。
         */
        size_t WritableSize() const;

        /**
         * @brief 将缓冲区中的数据转换为指定类型的指针，方便读取该类型的数据
         */
        template<class T>
        const T* As() const { return reinterpret_cast<const T*>(GetDataBegin()); }

        bool IsValid() const { return is_valid_; }
    private:
        /**
         * @brief 只允许BufferPoolManager创建有效的WriteBufferGuard对象
         */
        explicit WriteBufferGuard(std::shared_ptr<BufferHeader> buffer);
    
    private:
        std::shared_ptr<BufferHeader> buffer_;
        bool is_valid_ = false;
        std::unique_lock<std::mutex> lock_;
    };
} // namespace adalog